-
Notifications
You must be signed in to change notification settings - Fork 274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add behind proxy middleware #590
base: main
Are you sure you want to change the base?
Conversation
Uses existing plack middlewares (ReverseProxy and ReverseProxyPath) to handle all request header modification when operating behing a proxy. Allows for variants (eg HTTP_X_FORWARDED_PROTOCOL) supported by Dancer(2) but not from those existing ReverseProxy middleware. Special cases REQUEST_BASE header to work with ReverseProxyPath so proxies from/to non-root paths "just work"(tm). (Alternate to #571.) As a middleware, devs get more flexability as to where to apply it; they can use Plack::Builder to wrap this around their app as well as further path/header altering middleware. This could be released as a seperate package; its not Dancer2 specific.
Conditionally apply BehindProxy middleware if behind_proxy is set. Making the "behind_proxy" option a global trigger that updates the Dancer 2::Runner object when set behind_proxy => 1; is run so the reverse proxy middleware can be conditionally wrapped around applications psgi coderef. We now 'use' the middleware directly rather than letting Placl::Builder load it for us. May allow earlier version of Placl to be used as a dependency.
Includes tests when proxy is not from root (see #571) Removes tests for ftp as the protocol behing a http proxy - it was silly and ReverseProxy middleware doesn't support it.
This is a whole lot. Can we have a discussion about it first? I like some ideas here, but others scare me, to be honest. |
The Pr was to initiate that discussion. Have I opened a can of worms? ;) |
So a rough assessment from me:
So that's my quick brain dump. :) |
Thanks @xsawyerx ! Lots of positives there (and nothing really scary). I suspect that if the issue that prompted adding As far as I'm aware there are no standards for those headers. Is it worth considering |
I forgot to mention (since I wrote it quickly) that the work you've done here is really good. I was really happy you sunk your teeth in it, and it seems very well thought-out. I agree that we would just say people should use the existing middleware. That's definitely the direction for us too. I'm still not sure about the situation of ReverseProxyPath. Are we sure it's something that shouldn't be done in |
ReverseProxyPath is more general than URLMap, I can go into details if needed.. We could take the approach of using the @xsawyerx I'm happy to prepare another PR with this approach if you think its a better fit. |
Maybe I'm being too presumptuous, but isn't it also possible to add this solution to the cookbook as something that can be done using Either way, getting |
Currently, Core::Request's is_behind_proxy is set by Core::App whenever a new Core::Context is provided (using a trigger, no less). There are various problems with this: * The App shouldn't care about is_behind_proxy * The attribute shouldn't be set every time, since it's global * Core::Context is unrelated to this Instead, we made behind_proxy a global variable (as done by GH #590) with its own trigger. Then it is set on instantiation by Core::Dispatcher. Then we can remove Core::App's _init_for_context method completely. GH #590 approaches this issue in an entirely different and better way, by suggesting we simply correct the environment before all of this happens using a middleware. For now we're just doing enough to untangle Core::Context more.
Currently, Core::Request's is_behind_proxy is set by Core::App whenever a new Core::Context is provided (using a trigger, no less). There are various problems with this: * The App shouldn't care about is_behind_proxy * The attribute shouldn't be set every time, since it's global * Core::Context is unrelated to this Instead, we made behind_proxy a global variable (as done by GH #590) with its own trigger. Then it is set on instantiation by Core::Dispatcher. Then we can remove Core::App's _init_for_context method completely. GH #590 approaches this issue in an entirely different and better way, by suggesting we simply correct the environment before all of this happens using a middleware. For now we're just doing enough to untangle Core::Context more.
Currently, Core::Request's is_behind_proxy is set by Core::App whenever a new Core::Context is provided (using a trigger, no less). There are various problems with this: * The App shouldn't care about is_behind_proxy * The attribute shouldn't be set every time, since it's global * Core::Context is unrelated to this Instead, we made behind_proxy a global variable (as done by GH #590) with its own trigger. Then it is set on instantiation by Core::Dispatcher. Then we can remove Core::App's _init_for_context method completely. GH #590 approaches this issue in an entirely different and better way, by suggesting we simply correct the environment before all of this happens using a middleware. For now we're just doing enough to untangle Core::Context more.
I want to rebase and merge it, but I have one question: |
The only reason I put it under the Dancer2 namespace is that is is kinda Dancer2 specific; some of the headers that are checked are non-standard ones that only Dancer1/2 have core support for. I'm happy to release it as a separate package; just need a sane name. Maybe |
Are they really Dancer-specific? Considering people are hitting these problems on production, wouldn't it mean they should be theoretically supported by others? My question is rather, is it simply a matter of others not noticing them or only us recognizing them? Is it our special brand of HTTP or is it simply a convention few follow? Ya know what I mean? |
Here's a (not so short) rundown of the three "non-standard" parts to the middleware in this Pr.
I think the summary of that is; If we stick to "defacto" headers that the ReverseProxy and ReverseProxyPath middleware use, we do not need to release further middleware, but will need to help some users in that migration. Did I just volunteer to write some docs..? |
This is a very old pull request with a complicated discussion. So if you have a compelling reason to keep it open, please speak up. Otherwise I will consider to close it soon. |
@racke yes its old, but please leave the PR as is. |
🤷 |
Reviewed this with @cromedome. Here's a summary of our thoughts:
|
Collects the request header munging that was being done when building the Request object into a Plack middleware (wraps existing Plack middlewares for request munging behind proxies).
Simplifies the request object (before tackling #589) and adds support for reverse proxies from non-root paths (#571). Devs can (conditionally) apply the middleware (via Plack::Builder) to provide more flexibility than was previously possible (eg BehindProxy -> MultiLang middleware-> Dancer app ).
I'm not 100% convinced that
behind_proxy
should be a global config item though - yell if you have opinions :D